package net.pulseproject.commons.midi;

import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Receiver;
import javax.sound.midi.ShortMessage;
import javax.sound.midi.Transmitter;
import javax.sound.midi.MidiDevice.Info;

import net.pulseproject.commons.midi.entity.DeviceKind;
import net.pulseproject.commons.midi.entity.DeviceState;
import net.pulseproject.commons.midi.entity.MessageTemplate;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class DebuggerLogic {
	
	private static final Log LOG = LogFactory.getLog(DebuggerLogic.class);
	
	public final void sendMidi(final String port, final MessageTemplate template) throws MidiUnavailableException {
		LOG.debug("sendMidi(port=[" + port + "], template=" + template + ")");
		
		final ShortMessage message = template.build();
		final MidiDevice device = this.loadDevice(port, DeviceKind.TRANSMITTER);
		final Receiver receiver = device.getReceiver();
		receiver.send(message, 0);
		receiver.close();
	}

	public final void addReceiver(final String port, final Receiver receiver) throws MidiUnavailableException {
		LOG.debug("addReceiverCollector(port=[" + port + "], receiver)");
		final MidiDevice device = this.loadDevice(port, DeviceKind.RECEIVER);
		final Transmitter transmitter = device.getTransmitter();
		final Receiver oldReceiver = transmitter.getReceiver();
		if(oldReceiver != null) {
			throw new RuntimeException("oldReceiver != null: " + oldReceiver);
		}
		transmitter.setReceiver(receiver);
	}
	
	private MidiDevice loadDevice(final String desiredPort, final DeviceKind kind) throws MidiUnavailableException {
		
		final Info[] infos = MidiSystem.getMidiDeviceInfo();
		for (final Info info : infos) {
			final String port = info.getName();
			if(port.equals(desiredPort)) {
				final MidiDevice device = MidiSystem.getMidiDevice(info);
				final int maxCount = kind.stateIsApplicable(DeviceState.RECEIVING_ONLY) ?
										device.getMaxTransmitters() :
										device.getMaxReceivers();
				if(maxCount != 0) {
					return device;
				}
			}
		}
		throw new RuntimeException("Could not find device by port [" + desiredPort + "]!");
	}
}
